﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Compilation;
using System.Reflection;

namespace Doo.Extension
{
    /// <summary>
    /// 代码含义帮助器
    /// </summary>
    public class CodeMeaningHelper
    {
        protected static Dictionary<Type, Dictionary<string, CodeMeaningAttribute>> CachedData = new Dictionary<Type, Dictionary<string, CodeMeaningAttribute>>();
        protected static Dictionary<Type, Type> FilterType = new Dictionary<Type, Type>();

        protected static Dictionary<string, CodeMeaningAttribute> LoadMeaning(Type type)
        {
            CodeMeaningFilterAttribute filterAttr = type.GetCustomAttributes(typeof(CodeMeaningFilterAttribute), true).FirstOrDefault() as CodeMeaningFilterAttribute;
            Type filtertype=null;
            if (filterAttr != null)
            {
                filtertype = filterAttr.FilterType;
            }
            FilterType.Add(type, filtertype);

            Dictionary<string, CodeMeaningAttribute> data = new Dictionary<string, CodeMeaningAttribute>();
            FieldInfo[] consts;
            if (type.IsEnum)
            {
                consts = type.GetFields(BindingFlags.Static | BindingFlags.Public).Where(r => r.FieldType == typeof(int)).ToArray();
            }
            else
            {
                consts = type.GetFields(BindingFlags.Static | BindingFlags.Public).Where(r => r.FieldType == typeof(string)).ToArray();
            }
            foreach (var c in consts)
            {
                var attrs = c.GetCustomAttributes(typeof(CodeMeaningAttribute), true);
                if (attrs.Length == 0) continue;
                CodeMeaningAttribute att = (CodeMeaningAttribute)attrs[0];
                string code = c.GetRawConstantValue().ToString();
                data.Add(code, att);
            }
            return data;
        }

        public static Dictionary<string, string> GetCodeMeanings(Type type, string filter)
        {
            // string to int
            Type filtertype = FilterType[type];
            object value = Enum.Parse(filtertype, filter, true);
            if (value == null) { throw new Exception(string.Format("{0} is not a valid value of {1}", filter, filtertype)); }
            return GetCodeMeanings(type, (int)value);
        }

        public static Dictionary<string, string> GetCodeMeanings(Type type, int filter)
        {
            Dictionary<string, string> dict = new Dictionary<string, string>();
            Dictionary<string,CodeMeaningAttribute> typedData;
            if (!CachedData.ContainsKey(type))
            {
                typedData = LoadMeaning(type);
                CachedData.Add(type, typedData);
            }
            else
            {
                typedData = CachedData[type];
            }
            //start filter
            foreach (var c in typedData)
            {
                if (filter > 0 && (filter & c.Value.Filter) == 0) continue;
                string code = c.Key;
                string meaning = c.Value.Meaning;
                dict.Add(code,meaning);
            }
            return dict;
        }
    }

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Enum)]
    public class CodeMeaningFilterAttribute : Attribute
    {
        private Type filterType;
        public Type FilterType { get { return filterType; } }

        public CodeMeaningFilterAttribute(Type type)
        {
            filterType = type;
        }
    }

    [AttributeUsage(AttributeTargets.Field)]
    public class CodeMeaningAttribute : Attribute
    {
        private string _meaning;
        /// <summary>
        /// 含义
        /// </summary>
        public string Meaning { get { return _meaning; } }

        private int _filter;
        /// <summary>
        /// 过滤
        /// </summary>
        public int Filter { get { return _filter; } }

        public CodeMeaningAttribute(string meaning)
        {
            _meaning = meaning;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="meaning"></param>
        /// <param name="filter">filter by bit</param>
        public CodeMeaningAttribute(string meaning, int filter)
        {
            _meaning = meaning;
            _filter = filter;
        }
    }

}
